from time import sleep

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.select import Select
from appium.webdriver.common.mobileby import MobileBy

from common import settings
from common.settings import TEST_IP, HUB_IP, TEST_PORT, HUB_PORT
from common.settings import ACCOUNT, PASSWORD
from common.settings import CHROME_DRIVER, CHROME_CAPABILITIES
from common.settings import LOGIN_ACCOUNT_XPATH, LOGIN_PASSWORD_XPATH, LOGIN_BUTTON_XPATH
from common.vue.float_window import WarningWindow
from common.vue.message import VueMessage


# Map PageElement constructor arguments to webdriver locator enums
LOCATOR_LIST = {
    # selenium
    'css': By.CSS_SELECTOR,
    'id_': By.ID,
    'name': By.NAME,
    'xpath': By.XPATH,
    'link_text': By.LINK_TEXT,
    'partial_link_text': By.PARTIAL_LINK_TEXT,
    'tag': By.TAG_NAME,
    'class_name': By.CLASS_NAME,
    # appium
    'ios_uiautomation': MobileBy.IOS_UIAUTOMATION,
    'ios_predicate': MobileBy.IOS_PREDICATE,
    'ios_class_chain': MobileBy.IOS_CLASS_CHAIN,
    'android_uiautomator': MobileBy.ANDROID_UIAUTOMATOR,
    'android_viewtag': MobileBy.ANDROID_VIEWTAG,
    'android_datamatcher': MobileBy.ANDROID_DATA_MATCHER,
    'accessibility_id': MobileBy.ACCESSIBILITY_ID,
    'image': MobileBy.IMAGE,
    'custom': MobileBy.CUSTOM,
}


class PageObject:
    """
    Page Object pattern.
    """

    def __init__(self, uri, is_login_page=False, account=ACCOUNT, password=PASSWORD):
        """
        :param driver: `selenium.webdriver.WebDriver` Selenium webdriver instance
        :param url: `str`
        Root URI to base any calls to the ``PageObject.get`` method. If not defined
        in the constructor it will try and look it from the webdriver object.
        """
        self.root_uri = 'https://{}:{}/#'.format(TEST_IP, TEST_PORT)

        if settings.DEBUG:
            self.driver = webdriver.Chrome(executable_path=CHROME_DRIVER)
        else:
            self.driver = webdriver.Remote('http://{}:{}/wd/hub'.format(HUB_IP, HUB_PORT),
                                      desired_capabilities=CHROME_CAPABILITIES)
        self.driver.maximize_window()
        self.driver.get(self.root_uri + uri)
        self.driver.implicitly_wait(5)
        if not is_login_page:
            self.__login(account, password)
            self.__weak_password_warning()
            self.get(uri)
            sleep(1)

    def __login(self, a, p):
        """提供给非登录页功能测试"""
        account = self.driver.find_element_by_xpath(LOGIN_ACCOUNT_XPATH)
        password = self.driver.find_element_by_xpath(LOGIN_PASSWORD_XPATH)
        login_btn = self.driver.find_element_by_xpath(LOGIN_BUTTON_XPATH)
        account.send_keys(a)
        sleep(1)
        password.send_keys(p)
        login_btn.click()
        sleep(3)

    def __weak_password_warning(self):
        fw = WarningWindow(self.driver)
        fw.confirm.click()
        sleep(1)

    def get(self, uri):
        """
        :param uri:  URI to GET, based off of the root_uri attribute.
        """
        root_uri = self.root_uri or ''
        self.driver.get(root_uri + uri)

    @property
    def message(self):
        return VueMessage(self.driver)

class PageSelect(object):
    """
    Processing select drop-down selection box
    """
    def __init__(self, select_elem, value=None, text=None, index=None):
        if value is not None:
            Select(select_elem).select_by_value(value)
        elif text is not None:
            Select(select_elem).select_by_visible_text(text)
        elif index is not None:
            Select(select_elem).select_by_index(index)
        else:
            raise ValueError('"value" or "text" or "index" options can not be all empty.')


class PageWait(object):

    def __init__(self, elm, timeout=10):
        """
        wait webelement display
        """
        try:
            timeout_int = int(timeout)
        except TypeError:
            raise ValueError("Type 'timeout' error, must be type int() ")

        for i in range(timeout_int):
            if elm is not None:
                if elm.is_displayed() is True:
                    break
                else:
                    sleep(1)
            else:
                sleep(1)
        else:
            raise TimeoutError("Timeout, element invisible")